﻿/*
Copyright (c) 2010, hiSoft
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the hiSoft nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE HISOFT AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL HISOFT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;

namespace Orchard.Test.Library
{
    public class WidgetHelper : UIHelperBase
    {
        public ContentItemHelper ContentItemHelper;
        public BlogHelper BlogHelper;

        public WidgetHelper(TestLibrary settings)
            : base(settings)
        {
            ContentItemHelper = new ContentItemHelper(settings);
            BlogHelper = new BlogHelper(settings);
        }

        private int GetLayerIdByName(WidgetLayer layer)
        {
            ManageWidgets();
            var layerId = -1;
            var widgetLayersCount = (int)selenium.GetXpathCount(WidgetLayersLocator);
            var layerIndex = 1;
            for (; layerIndex <= widgetLayersCount; layerIndex++)
            {
                string layerNameLocator = String.Format("{0}[{1}]", WidgetLayersLocator, layerIndex);
                var text = selenium.GetText(layerNameLocator);
                if (String.CompareOrdinal(layer.Name, text) == 0)
                {
                    layerId = Int32.Parse(selenium.GetAttribute(String.Format("{0}/@value", layerNameLocator)));
                    break;
                }
            }

            if (layerIndex > widgetLayersCount)
                throw new CaseFailureException(String.Format("Can't find widgetLayer {0} in Manage Widgets page!", layer.Name));

            return layerId;
        }

        public int GetWidgetLayerId(WidgetLayer layer)
        {
            if (layer == null)
            {
                layer = new WidgetLayer("Default");
            }

            return GetLayerIdByName(layer);
        }

        public int GetWidgetIdByTitle(Widget widget)
        {
            var widgetId = -1;
            var widgetZonesCount = (int)selenium.GetXpathCount(WidgetZonesLocator);
            var index = 1;
            for (; index <= widgetZonesCount; index++)
            {
                string widgetZoneName = selenium.GetText(String.Format("{0}[{1}]/h2", WidgetZonesLocator, index));
                if (widgetZoneName == Enum.GetName(typeof(WidgetZone), widget.WidgetZone))
                {
                    string widgetsLocator = String.Format("{0}[{1}]/ul/li", WidgetZonesLocator, index);
                    var widgetsCount = (int)selenium.GetXpathCount(widgetsLocator);
                    for (int j = 1; j <= widgetsCount; j++)
                    {
                        string widgetTitleLocator = String.Format("{0}[{1}]/form/h3/a", widgetsLocator, j);
                        if (selenium.GetText(widgetTitleLocator) == widget.Title)
                        {
                            string idStr = selenium.GetAttribute(String.Format("{0}/@href", widgetTitleLocator));
                            string[] idStrs = idStr.Split('/');
                            int intFlag = idStrs[idStrs.Length - 1].IndexOf('?');
                            widgetId = Int32.Parse(idStrs[idStrs.Length - 1].Substring(0, intFlag));
                            break;
                        }
                    }
                    break;
                }
            }

            if (index > widgetZonesCount)
                widgetId = -1;

            return widgetId;
        }

        private void AddWidget(WidgetType widgetType, WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner)
        {
            var widgetLayerId = GetWidgetLayerId(widgetLayer);
            string widgetTypeName = Enum.GetName(typeof(WidgetType), widgetType);
            string widgetZoneName = Enum.GetName(typeof(WidgetZone), widgetZone);
            selenium.Open(String.Format("/Admin/Widgets/AddWidget?layerId={0}&widgetType={1}&zone={2}", widgetLayerId, widgetTypeName, widgetZoneName));
            selenium.Type("Title", title);
            string positionStr = position.ToString();
            if (positionStr == "0")
            {
                positionStr = String.Empty;
            }
            selenium.Type("Position", positionStr);
            selenium.Type(OwnerLocator, owner);
        }

        public void NavigateToEditLayer(WidgetLayer widgetLayer)
        {
            ManageWidgets();
            selenium.Select("layerId", widgetLayer.Name);
            selenium.SetSpeed("1000");
            ClickAndWait("//div[@id='widgets-layers-control']/form/fieldset/a");
        }

        public void SetActiveLayerCurrent(WidgetLayer widgetLayer)
        {
            ManageWidgets();
            selenium.Select("layerId", widgetLayer.Name);            
        }

        public void ManageWidgets()
        {           
            selenium.Open("/Admin/Widgets");
        }

        public WidgetLayer AddWidgetLayer(string name)
        {
            return AddWidgetLayer(name, TestLibrary.Consts.AdminUserName);
        }

        public WidgetLayer AddWidgetLayer(string name, string owner)
        {
            return AddWidgetLayer(name, owner, null, null);
        }

        public WidgetLayer AddWidgetLayer(string name, string owner, string description, string layerRule)
        {
            selenium.Open("/Admin/Widgets/AddLayer");
            selenium.Type("Name", name);
            selenium.Type("Description", description);
            selenium.Type("LayerRule", layerRule);
            selenium.Type(OwnerLocator, owner);
            Submit();
            return new WidgetLayer(name, owner, description, layerRule);
        }

        public WidgetLayer EditCurrentWidgetLayer(string name, string owner, string description, string layerRule)
        {
            selenium.Type("Name", name);
            selenium.Type("Description", description);
            selenium.Type("LayerRule", layerRule);
            selenium.Type(OwnerLocator, owner);
            Submit();
            return new WidgetLayer(name, owner, description, layerRule);
        }

        public void DeleteCurrentWidgetLayer()
        {
            ClickAndWait("//button[@name='submit.Delete']");        
        }

        public WidgetLayer EditWidgetLayer(WidgetLayer layer, string newName)
        {
            NavigateToEditLayer(layer);
            selenium.Type("Name", newName);
            ClickAndWait("//button[@name='submit.Save']");
            return new WidgetLayer(newName, layer.Owner, layer.Description, layer.LayerRule);
        }

        public void DeleteWidgetLayer(WidgetLayer layer)
        {
            NavigateToEditLayer(layer);
            ClickAndWait("//button[@name='submit.Delete']");
        }

        public void DeleteAllWidgetLayers()
        {
            ManageWidgets();
            int intLayerCount=(int)selenium.GetXpathCount(UIHelperBase.WidgetLayersLocator);
            for (int layerIndex = 1; layerIndex <= intLayerCount; layerIndex++)
            {
                ClickAndWait("link=Edit");
                ClickAndWait("submit.Delete");                
            }
        }

        public string GetOwnerOfWidgetLayer(WidgetLayer layer)
        {
            NavigateToEditLayer(layer);
            return selenium.GetValue(OwnerLocator);
        }

        public Widget AddHtmlWidget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string body)
        {
            ManageWidgets();
            AddWidget(WidgetType.HtmlWidget, widgetLayer, widgetZone, title, position, owner);
            selenium.Type("Body_Text", body);
            if (String.IsNullOrEmpty(title))
            {
                title = "Html Widget";
            }
            var htmlWidget = new HtmlWidget(widgetLayer, widgetZone, title, position, owner, body);
            Submit();
            htmlWidget.Id = GetWidgetIdByTitle(htmlWidget);
            return htmlWidget;
        }

        public void AddHtmlWidgetWithoutSave(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string body)
        {
            ManageWidgets();
            AddWidget(WidgetType.HtmlWidget, widgetLayer, widgetZone, title, position, owner);
            selenium.Type("Body_Text", body);
            if (String.IsNullOrEmpty(title))
            {
                title = "Html Widget";
            }
            var htmlWidget = new HtmlWidget(widgetLayer, widgetZone, title, position, owner, body);
            //Submit();
            //htmlWidget.Id = GetWidgetIdByTitle(htmlWidget);
            //return htmlWidget;
        }

        public Widget AddRecentBlogPosts(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string forBlog, string count)
        {
            ManageWidgets();
            AddWidget(WidgetType.RecentBlogPosts, widgetLayer, widgetZone, title, position, owner);
            if (!string.IsNullOrEmpty(forBlog)) selenium.Select("Slug", forBlog);
            selenium.Type("Count", count);
            if (String.IsNullOrEmpty(title))
            {
                title = "Recent Blog Posts";
            }
            var recentBlogPosts = new RecentBlogPosts(widgetLayer, widgetZone, title, position, owner, forBlog, count);
            Submit();
            recentBlogPosts.Id = GetWidgetIdByTitle(recentBlogPosts);
            return recentBlogPosts;
        }

        public Widget AddBlogArchives(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string forBlog)
        {
            ManageWidgets();
            AddWidget(WidgetType.BlogArchives, widgetLayer, widgetZone, title, position, owner);
            if (!string.IsNullOrEmpty(forBlog)) selenium.Select("Path", forBlog);
            if (String.IsNullOrEmpty(title))
            {
                title = "Blog Archives";
            }
            var blogArchives = new BlogArchives(widgetLayer, widgetZone, title, position, owner, forBlog);
            Submit();
            blogArchives.Id = GetWidgetIdByTitle(blogArchives);
            return blogArchives;
        }

        public void AddSearchForm()
        {
            ManageWidgets();
            AddWidget(WidgetType.SearchForm, new WidgetLayer("Default"), WidgetZone.Header, null, 1, TestLibrary.Consts.AdminUserName);
            Submit();
        }

        public Widget AddContainerWidget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title)
        {
            return AddContainerWidget(widgetLayer, widgetZone, title, 1, "admin", null, 5, "", "",false, "","", "");
        }

        public Widget AddContainerWidget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, Lists containerId, int pageSize, string orderByProperty, string orderByDirection, bool applyFilter, string filterByProperty, string filterByOperator, string filtetByValue)
        {
            ManageWidgets();
            AddWidget(WidgetType.ContainerWidget, widgetLayer, widgetZone, title, position, owner);
            if ((containerId != null))
            {
                selenium.Select("ContainerWidget_Part_Record_ContainerId", String.Format("List: {0}", containerId.Title));
            }
            string pageSizeStr = pageSize.ToString();
            if (pageSizeStr == "0")
            {
                pageSizeStr = String.Empty;
            }
            selenium.Type("ContainerWidget_Part_Record_PageSize", pageSizeStr);
            if (!String.IsNullOrEmpty(orderByProperty))
            {
                selenium.Select("ContainerWidget_Part_Record_OrderByProperty", orderByProperty);
            }
            if (!String.IsNullOrEmpty(orderByDirection))
            {
                selenium.Select("ContainerWidget_Part_Record_OrderByDirection", orderByDirection);
            }
            if (applyFilter)
            {
                selenium.Check("ContainerWidget_Part_Record_ApplyFilter");
                if (!String.IsNullOrEmpty(filterByProperty))
                {
                    selenium.Select("ContainerWidget_Part_Record_FilterByProperty", filterByProperty);
                }
                if (!String.IsNullOrEmpty(filterByOperator))
                {
                    selenium.Select("ContainerWidget_Part_Record_FilterByOperator", filterByOperator);

                }
                selenium.Type("ContainerWidget_Part_Record_FilterByValue", filtetByValue);
            }
            else
            {
                selenium.Uncheck("ContainerWidget_Part_Record_ApplyFilter");
            }
            if (String.IsNullOrEmpty(title))
            {
                title = "Container Widget";
            }
            var containerWidget = new ContainerWidget(widgetLayer, widgetZone, title, position, owner, containerId, pageSize, orderByProperty, orderByDirection, applyFilter);
            Submit();
            containerWidget.Id = GetWidgetIdByTitle(containerWidget);
            return containerWidget;
        }

        public Widget EditWidget(Widget widget, WidgetLayer newLayer, WidgetZone newZone, string newTitle, int newPosition)
        {
            selenium.Open(String.Format("/Admin/Widgets/EditWidget/{0}", widget.Id));            
            selenium.Select("Zone", Enum.GetName(typeof(WidgetZone), newZone));
            selenium.Select("LayerId", newLayer.Name);
            selenium.Type("Position", newPosition.ToString());
            selenium.Type("Title", newTitle);
            ClickAndWait("//button[@name='submit.Save']");

            widget.WidgetLayer = newLayer;
            widget.WidgetZone = newZone;
            widget.Position = newPosition;
            widget.Title = newTitle;
            return widget;
        }

        public void DeleteWidget(Widget widget)
        {
            selenium.Open(String.Format("/Admin/Widgets/EditWidget/{0}", widget.Id));
            ClickAndWait("//button[@name='submit.Delete']");
        }

        public void MoveWidget(Widget widget, WidgetLayer layerTo)
        {
            ManageWidgets();
            selenium.SetSpeed("1000");
            selenium.Select("//select[@id='layerId']", layerTo.Name);
            ClickAndWait("//button[@name='moveHere']");
        }

        public void RemoveWidget(Widget widget)
        {
            ManageWidgets();
            selenium.Select("//select[@id='layerId']", widget.WidgetLayer.Name);
            ClickAndWait("//button[@name='moveOut']");
        }

        /// <summary>
        /// Check if a widget layer exist
        /// </summary>
        /// <param name="widgetName"></param>
        /// <returns></returns>
        public bool IsWidgetLayerExist(string widgetLayerName)
        {
            if (!selenium.GetLocation().Contains("/Admin/Widgets"))
                ManageWidgets();
            string[] selectOptions = selenium.GetSelectOptions("//select[@id='layerId']");
            for (int i = 0; i < selectOptions.Length; i++)
            {
                if (selectOptions[i] == widgetLayerName)
                    return true;
            }             
            return false;
        }

        public int GetIndexOfWidgetZone()
        {
            return 0;  
        }

        public void MoveUpWidget(Widget widget)
        {
            //
        }

        public void MoveDownWidget(Widget widget)
        {
            //
        }

        public string GetLayerOfWidgetLocated(string widigetName)
        {
            if (selenium.IsElementPresent("link=" + widigetName))
                ClickAndWait("link=" + widigetName);
            else return "";
            return selenium.GetSelectedLabel("LayerId");
        }


    }

    public class WidgetLayer
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string LayerRule { get; set; }
        public string Owner { get; set; }

        public WidgetLayer(string name)
        {
            Name = name;
        }

        public WidgetLayer(string name, string description, string layerRule, string owner)
        {
            Name = name;
            Description = description;
            LayerRule = layerRule;
            Owner = owner;
        }
    }

    public class Widget
    {
        public WidgetLayer WidgetLayer { get; set; }
        public WidgetZone WidgetZone { get; set; }
        public string Title { get; set; }
        public int Position { get; set; }
        public string Owner { get; set; }
        public int Id { get; set; }

        public Widget() { }

        public Widget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner)
        {
            WidgetLayer = widgetLayer;
            WidgetZone = widgetZone;
            Title = title;
            Position = position;
            Owner = owner;
        }
    }   

    public class RecentBlogPosts : Widget
    {
        public string ForBlog { get; set; }
        public string Count { get; set; }

        public RecentBlogPosts(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string forBlog, string count)
            :base(widgetLayer, widgetZone, title, position, owner)
        {        
            ForBlog = forBlog;
            Count = count;    
        }
    }

    public class BlogArchives : Widget
    {
        public string ForBlog { get; set; } 

        public BlogArchives(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string forBlog)
            :base(widgetLayer, widgetZone, title, position, owner)
        {        
            ForBlog = forBlog;      
        } 
    }

    public class HtmlWidget : Widget
    {
        public string Body { get; set; }

        public HtmlWidget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, string body)
            : base(widgetLayer, widgetZone, title, position, owner)
        {
            Body = body;
        }
    }

    public class SearchForm : Widget
    {       
       
    }

    public class ContainerWidget : Widget
    {
        public Lists ContainerId { get; set; }
        public int PageSize { get; set; }
        public string OrderByProperty { get; set; }
        public string OrderByDirection { get; set; }
        public bool ApplyFilter { get; set; }

        public ContainerWidget(WidgetLayer widgetLayer, WidgetZone widgetZone, string title, int position, string owner, Lists containerId, int pageSize, string orderByProperty, string orderByDirection, bool applyFilter)
            : base(widgetLayer, widgetZone, title, position, owner)
        {
            ContainerId = containerId;
            PageSize = pageSize;
            OrderByProperty = orderByProperty;
            OrderByDirection = orderByDirection;
            ApplyFilter = applyFilter;
        } 
    }

    public enum WidgetZone
    {
        Header,
        Navigation,
        Featured,
        BeforeMain,
        Messages,
        BeforeContent,
        Content,
        AfterContent,
        AfterMain,
        TripelFirst,
        TripelSecond,
        TripelThird,
        FooterQuadFirst,
        FooterQuadSecond,
        FooterQuadThird,
        FooterQuadFourth,
        Footer,
        AsideFirst,
        AsideSecond
    }

    public enum WidgetType
    {
        RecentBlogPosts,
        BlogArchives,
        HtmlWidget,
        SearchForm,
        ContainerWidget
    }
}
